﻿Imports System
Imports System.Collections
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Namespace System.Workflow.ComponentModel.Design
    Friend NotInheritable Class PrintPreviewLayout
        Inherits WorkflowLayout
        ' Methods
        Friend Sub New(ByVal serviceProvider As IServiceProvider, ByVal printDoc As WorkflowPrintDocument)
            MyBase.New(serviceProvider)
            Me.pageLayoutInfo = New ArrayList
            Me.headerFooterMargins = New Margins(0, 0, 0, 0)
            Me.pageSeparator = PrintPreviewLayout.DefaultPageSeparator
            Me.pageMargins = PrintPreviewLayout.DefaultPageMargins
            Me.rowColumns = New Size(1, 1)
            Me.scaling = 1!
            Me.pageSize = Size.Empty
            Me.previewTime = DateTime.Now
            Me.printDocument = printDoc
        End Sub

        Private Function GetAdjustedMargins(ByVal graphics As Graphics) As Margins
            Dim margins As Margins = Me.printDocument.PageSetupData.Margins
            If Me.printDocument.PageSetupData.Landscape Then
                Dim left As Integer = margins.Left
                margins.Left = margins.Right
                margins.Right = left
                left = margins.Bottom
                margins.Bottom = margins.Top
                margins.Top = left
            End If
            Dim hardMargins As New Margins
            [Using] graphics2 As Graphics = Me.printDocument.PrinterSettings.CreateMeasurementGraphics
                hardMargins = Me.printDocument.GetHardMargins(graphics2)
            End [Using]
            Return New Margins(Math.Max(margins.Left, hardMargins.Left), Math.Max(margins.Right, hardMargins.Right), Math.Max(margins.Top, hardMargins.Top), Math.Max(margins.Bottom, hardMargins.Bottom))
        End Function

        Private Function GetPaperSize(ByVal graphics As Graphics) As Size
            Dim empty As Size = Size.Empty
            Dim paperSize As PaperSize = Me.printDocument.DefaultPageSettings.PaperSize
            Me.printDocument.DefaultPageSettings.PaperSize = paperSize
            If Me.printDocument.PageSetupData.Landscape Then
                empty.Width = Math.Max(paperSize.Height, 1)
                empty.Height = Math.Max(paperSize.Width, 1)
                Return empty
            End If
            empty.Width = Math.Max(paperSize.Width, 1)
            empty.Height = Math.Max(paperSize.Height, 1)
            Return empty
        End Function

        Public Overrides Function IsCoOrdInLayout(ByVal logicalCoOrd As Point) As Boolean
            Dim data As PageLayoutData
            For Each data In Me.pageLayoutInfo
                If data.ViewablePageBounds.Contains(logicalCoOrd) Then
                    Return True
                End If
            Next
            Return False
        End Function

        Public Overrides Function MapInCoOrdToLayout(ByVal logicalPoint As Point) As Point
            Dim data As PageLayoutData
            For Each data In Me.pageLayoutInfo
                If data.PageBounds.Contains(logicalPoint) Then
                    Dim point As New Point((logicalPoint.X - data.ViewablePageBounds.Left), (logicalPoint.Y - data.ViewablePageBounds.Top))
                    logicalPoint = New Point((data.LogicalPageBounds.Left + point.X), (data.LogicalPageBounds.Top + point.Y))
                    Return logicalPoint
                End If
            Next
            Return logicalPoint
        End Function

        Public Overrides Function MapInRectangleToLayout(ByVal logicalRectangle As Rectangle) As Rectangle
            Dim empty As Rectangle = Rectangle.Empty
            Dim data As PageLayoutData
            For Each data In Me.pageLayoutInfo
                Dim rectangle2 As Rectangle = logicalRectangle
                rectangle2.Intersect(data.ViewablePageBounds)
                If Not rectangle2.IsEmpty Then
                    Dim size As Size
                    Dim point As New Point((rectangle2.X - data.ViewablePageBounds.X), (rectangle2.Y - data.ViewablePageBounds.Y))
                    size = New Size((data.ViewablePageBounds.Width - rectangle2.Width), (data.ViewablePageBounds.Height - rectangle2.Height)) { _
                        .Width = (size.Width - point.X), _
                        .Height = (size.Height - point.Y) _
                    }
                    Dim b As Rectangle = Rectangle.Empty
                    b.X = (data.LogicalPageBounds.X + point.X)
                    b.Y = (data.LogicalPageBounds.Y + point.Y)
                    b.Width = (data.LogicalPageBounds.Width - point.X)
                    b.Width = (b.Width - size.Width)
                    b.Height = (data.LogicalPageBounds.Height - point.Y)
                    b.Height = (b.Height - size.Height)
                    empty = If(empty.IsEmpty, b, Rectangle.Union(empty, b))
                End If
            Next
            Return empty
        End Function

        Public Overrides Function MapOutCoOrdFromLayout(ByVal logicalPoint As Point) As Point
            Dim data As PageLayoutData
            For Each data In Me.pageLayoutInfo
                If data.LogicalPageBounds.Contains(logicalPoint) Then
                    Dim point As New Point((logicalPoint.X - data.LogicalPageBounds.Left), (logicalPoint.Y - data.LogicalPageBounds.Top))
                    logicalPoint = New Point((data.ViewablePageBounds.Left + point.X), (data.ViewablePageBounds.Top + point.Y))
                    Return logicalPoint
                End If
            Next
            Return logicalPoint
        End Function

        Public Overrides Function MapOutRectangleFromLayout(ByVal logicalRectangle As Rectangle) As Rectangle
            Dim empty As Rectangle = Rectangle.Empty
            Dim data As PageLayoutData
            For Each data In Me.pageLayoutInfo
                Dim rectangle2 As Rectangle = logicalRectangle
                rectangle2.Intersect(data.LogicalPageBounds)
                If Not rectangle2.IsEmpty Then
                    Dim size As Size
                    Dim point As New Point((rectangle2.X - data.LogicalPageBounds.X), (rectangle2.Y - data.LogicalPageBounds.Y))
                    size = New Size((data.LogicalPageBounds.Width - rectangle2.Width), (data.LogicalPageBounds.Height - rectangle2.Height)) { _
                        .Width = (size.Width - point.X), _
                        .Height = (size.Height - point.Y) _
                    }
                    Dim b As Rectangle = Rectangle.Empty
                    b.X = (data.ViewablePageBounds.X + point.X)
                    b.Y = (data.ViewablePageBounds.Y + point.Y)
                    b.Width = (data.ViewablePageBounds.Width - point.X)
                    b.Width = (b.Width - size.Width)
                    b.Height = (data.ViewablePageBounds.Height - point.Y)
                    b.Height = (b.Height - size.Height)
                    empty = If(empty.IsEmpty, b, Rectangle.Union(empty, b))
                End If
            Next
            Return empty
        End Function

        Public Overrides Sub OnPaint(ByVal e As PaintEventArgs, ByVal viewPortData As ViewPortData)
            Dim graphics As Graphics = e.Graphics
            Dim ambientTheme As AmbientTheme = WorkflowTheme.CurrentTheme.AmbientTheme
            Dim memoryBitmap As Bitmap = viewPortData.MemoryBitmap
            graphics.FillRectangle(Brushes.White, New Rectangle(Point.Empty, memoryBitmap.Size))
            If (Not ambientTheme.WorkflowWatermarkImage Is Nothing) Then
                Dim container As GraphicsContainer = graphics.BeginContainer
                Dim matrix As New Matrix
                matrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend)
                matrix.Invert
                Dim pts As Point() = New Point() { viewPortData.Translation, New Point(viewPortData.ViewPortSize) }
                matrix.TransformPoints(pts)
                Dim rect As New Rectangle(pts(0), New Size(pts(1)))
                matrix = New Matrix
                matrix.Scale(((viewPortData.Scaling.Width / CSng(MyBase.parentView.Zoom)) * 100!), ((viewPortData.Scaling.Height / CSng(MyBase.parentView.Zoom)) * 100!))
                Dim matrix2 As New Matrix
                matrix2.Scale((CSng(MyBase.parentView.Zoom) / 100!), (CSng(MyBase.parentView.Zoom) / 100!))
                graphics.Transform = matrix2
                Dim data As PageLayoutData
                For Each data In Me.pageLayoutInfo
                    If data.PageBounds.IntersectsWith(rect) Then
                        Dim empty As Rectangle = Rectangle.Empty
                        empty.X = (data.LogicalPageBounds.X - viewPortData.LogicalViewPort.X)
                        empty.Y = (data.LogicalPageBounds.Y - viewPortData.LogicalViewPort.Y)
                        empty.Width = data.LogicalPageBounds.Width
                        empty.Height = data.LogicalPageBounds.Height
                        pts = New Point() { empty.Location, New Point(empty.Size) }
                        matrix.TransformPoints(pts)
                        empty.Location = pts(0)
                        empty.Size = New Size(pts(1))
                        ActivityDesignerPaint.DrawImage(graphics, ambientTheme.WorkflowWatermarkImage, empty, New Rectangle(Point.Empty, ambientTheme.WorkflowWatermarkImage.Size), ambientTheme.WatermarkAlignment, 0.25!, False)
                    End If
                Next
                graphics.EndContainer(container)
            End If
        End Sub

        Public Overrides Sub OnPaintWorkflow(ByVal e As PaintEventArgs, ByVal viewPortData As ViewPortData)
            Dim graphics As Graphics = e.Graphics
            Dim memoryBitmap As Bitmap = viewPortData.MemoryBitmap
            Dim ambientTheme As AmbientTheme = WorkflowTheme.CurrentTheme.AmbientTheme
            Dim container As GraphicsContainer = graphics.BeginContainer
            Dim rect As New Rectangle(Point.Empty, memoryBitmap.Size)
            graphics.FillRectangle(AmbientTheme.WorkspaceBackgroundBrush, rect)
            [Using] font As Font = New Font(ambientTheme.Font.FontFamily, (ambientTheme.Font.Size / Me.scaling), ambientTheme.Font.Style)
                Dim num As Integer = 0
                Dim matrix As New Matrix
                Dim matrix2 As New Matrix
                matrix2.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend)
                matrix2.Invert
                Dim pts As Point() = New Point() { viewPortData.Translation, New Point(viewPortData.ViewPortSize) }
                matrix2.TransformPoints(pts)
                matrix2.Invert
                Dim rectangle2 As New Rectangle(pts(0), New Size(pts(1)))
                Dim headerFooterPrintData As New HeaderFooterData { _
                    .HeaderFooterMargins = Me.headerFooterMargins, _
                    .PrintTime = Me.previewTime, _
                    .TotalPages = Me.pageLayoutInfo.Count, _
                    .Scaling = Me.scaling, _
                    .Font = font _
                }
                Dim service As WorkflowDesignerLoader = [TryCast](MyBase.serviceProvider.GetService(GetType(WorkflowDesignerLoader)),WorkflowDesignerLoader)
                headerFooterPrintData.FileName = If((Not service Is Nothing), service.FileName, String.Empty)
                Dim matrix3 As New Matrix
                matrix3.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend)
                matrix3.Translate(CSng(-viewPortData.Translation.X), CSng(-viewPortData.Translation.Y), MatrixOrder.Append)
                Dim data2 As PageLayoutData
                For Each data2 In Me.pageLayoutInfo
                    num += 1
                    If ((data2.PageBounds.IntersectsWith(rectangle2) AndAlso (data2.PageBounds.Width > 0)) AndAlso (data2.PageBounds.Height > 0)) Then
                        graphics.Transform = matrix3
                        graphics.FillRectangle(Brushes.White, data2.PageBounds)
                        ActivityDesignerPaint.DrawDropShadow(graphics, data2.PageBounds, Color.Black, 4, (LightSourcePosition.Top Or LightSourcePosition.Left), 0.2!, False)
                        Dim logicalPageBounds As Rectangle = data2.LogicalPageBounds
                        logicalPageBounds.Intersect(viewPortData.LogicalViewPort)
                        If Not logicalPageBounds.IsEmpty Then
                            graphics.Transform = matrix
                            Dim empty As Point = Point.Empty
                            empty.X = (data2.ViewablePageBounds.X + Math.Abs(CInt((data2.LogicalPageBounds.X - logicalPageBounds.X))))
                            empty.Y = (data2.ViewablePageBounds.Y + Math.Abs(CInt((data2.LogicalPageBounds.Y - logicalPageBounds.Y))))
                            pts = New Point() { empty }
                            matrix2.TransformPoints(pts)
                            empty = New Point((pts(0).X - viewPortData.Translation.X), (pts(0).Y - viewPortData.Translation.Y))
                            Dim source As Rectangle = Rectangle.Empty
                            source.X = (logicalPageBounds.X - viewPortData.LogicalViewPort.X)
                            source.Y = (logicalPageBounds.Y - viewPortData.LogicalViewPort.Y)
                            source.Width = logicalPageBounds.Width
                            source.Height = logicalPageBounds.Height
                            pts = New Point() { source.Location, New Point(source.Size) }
                            matrix2.TransformPoints(pts)
                            source.Location = pts(0)
                            source.Size = New Size(pts(1))
                            ActivityDesignerPaint.DrawImage(graphics, memoryBitmap, New Rectangle(empty, source.Size), source, DesignerContentAlignment.Fill, 1!, WorkflowTheme.CurrentTheme.AmbientTheme.DrawGrayscale)
                        End If
                        graphics.Transform = matrix3
                        graphics.DrawRectangle(Pens.Black, data2.PageBounds)
                        graphics.DrawRectangle(ambientTheme.ForegroundPen, CInt((data2.ViewablePageBounds.Left - 3)), CInt((data2.ViewablePageBounds.Top - 3)), CInt((data2.ViewablePageBounds.Width + 6)), CInt((data2.ViewablePageBounds.Height + 6)))
                        headerFooterPrintData.PageBounds = data2.PageBounds
                        headerFooterPrintData.PageBoundsWithoutMargin = data2.ViewablePageBounds
                        headerFooterPrintData.CurrentPage = num
                        If (Me.printDocument.PageSetupData.HeaderTemplate.Length > 0) Then
                            Me.printDocument.PrintHeaderFooter(graphics, True, headerFooterPrintData)
                        End If
                        If (Me.printDocument.PageSetupData.FooterTemplate.Length > 0) Then
                            Me.printDocument.PrintHeaderFooter(graphics, False, headerFooterPrintData)
                        End If
                    End If
                Next
                graphics.EndContainer(container)
            End [Using]
        End Sub

        Public Overrides Sub Update(ByVal graphics As Graphics, ByVal reason As LayoutUpdateReason)
            If (reason <> LayoutUpdateReason.ZoomChanged) Then
                Dim size5 As Size
                If (graphics Is Nothing) Then
                    Throw New ArgumentException("graphics")
                End If
                Dim margin As Size = WorkflowTheme.CurrentTheme.AmbientTheme.Margin
                Dim paperSize As Size = Me.GetPaperSize(graphics)
                Dim adjustedMargins As Margins = Me.GetAdjustedMargins(graphics)
                Dim size2 As Size = If((Not MyBase.parentView.RootDesigner Is Nothing), MyBase.parentView.RootDesigner.Size, Size.Empty)
                If Not size2.IsEmpty Then
                    Dim selectionSize As Size = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize
                    size2.Width = (size2.Width + (3 * selectionSize.Width))
                    size2.Height = (size2.Height + (3 * selectionSize.Height))
                End If
                If Me.printDocument.PageSetupData.AdjustToScaleFactor Then
                    Me.scaling = (CSng(Me.printDocument.PageSetupData.ScaleFactor) / 100!)
                Else
                    Dim size4 As Size
                    size4 = New Size((paperSize.Width - (adjustedMargins.Left + adjustedMargins.Right)), (paperSize.Height - (adjustedMargins.Top + adjustedMargins.Bottom))) { _
                        .Width = Math.Max(size4.Width, 1), _
                        .Height = Math.Max(size4.Height, 1) _
                    }
                    Dim tf As New PointF(((Me.printDocument.PageSetupData.PagesWide * size4.Width) / CSng(size2.Width)), ((Me.printDocument.PageSetupData.PagesTall * size4.Height) / CSng(size2.Height)))
                    Me.scaling = Math.Min(tf.X, tf.Y)
                    Me.scaling = CSng((Math.Floor(CDbl((Me.scaling * 1000))) / 1000))
                End If
                Me.pageSize = paperSize
                Me.pageSize.Width = Convert.ToInt32(Math.Ceiling(CDbl((CSng(Me.pageSize.Width) / Me.scaling))))
                Me.pageSize.Height = Convert.ToInt32(Math.Ceiling(CDbl((CSng(Me.pageSize.Height) / Me.scaling))))
                Dim service As IDesignerOptionService = [TryCast](MyBase.serviceProvider.GetService(GetType(IDesignerOptionService)),IDesignerOptionService)
                If (Not service Is Nothing) Then
                    Dim optionValue As Object = service.GetOptionValue("WinOEDesigner", "PageSeparator")
                    Me.PageSeparator = If((Not optionValue Is Nothing), DirectCast(optionValue, Size), PrintPreviewLayout.DefaultPageSeparator)
                End If
                Me.PageSeparator = New Size(Convert.ToInt32(Math.Ceiling(CDbl((CSng(Me.PageSeparator.Width) / Me.scaling)))), Convert.ToInt32(Math.Ceiling(CDbl((CSng(Me.PageSeparator.Height) / Me.scaling)))))
                Me.PageMargins = adjustedMargins
                Me.PageMargins.Left = Convert.ToInt32(CSng((CSng(Me.PageMargins.Left) / Me.scaling)))
                Me.PageMargins.Right = Convert.ToInt32(CSng((CSng(Me.PageMargins.Right) / Me.scaling)))
                Me.PageMargins.Top = Convert.ToInt32(CSng((CSng(Me.PageMargins.Top) / Me.scaling)))
                Me.PageMargins.Bottom = Convert.ToInt32(CSng((CSng(Me.PageMargins.Bottom) / Me.scaling)))
                Me.headerFooterMargins.Top = Convert.ToInt32(CSng((CSng(Me.printDocument.PageSetupData.HeaderMargin) / Me.scaling)))
                Me.headerFooterMargins.Bottom = Convert.ToInt32(CSng((CSng(Me.printDocument.PageSetupData.FooterMargin) / Me.scaling)))
                Me.previewTime = DateTime.Now
                size5 = New Size((Me.pageSize.Width - (Me.PageMargins.Left + Me.PageMargins.Right)), (Me.pageSize.Height - (Me.PageMargins.Top + Me.PageMargins.Bottom))) { _
                    .Width = Math.Max(size5.Width, 1), _
                    .Height = Math.Max(size5.Height, 1) _
                }
                Me.rowColumns.Width = (size2.Width / size5.Width)
                Me.rowColumns.Width = (Me.rowColumns.Width + If(((size2.Width Mod size5.Width) > 1), 1, 0))
                Me.rowColumns.Width = Math.Max(1, Me.rowColumns.Width)
                Me.rowColumns.Height = (size2.Height / size5.Height)
                Me.rowColumns.Height = (Me.rowColumns.Height + If(((size2.Height Mod size5.Height) > 1), 1, 0))
                Me.rowColumns.Height = Math.Max(1, Me.rowColumns.Height)
                Me.pageLayoutInfo.Clear
                Dim i As Integer
                For i = 0 To Me.rowColumns.Height - 1
                    Dim j As Integer
                    For j = 0 To Me.rowColumns.Width - 1
                        Dim empty As Point = Point.Empty
                        empty.X = ((j * Me.pageSize.Width) + ((j + 1) * Me.PageSeparator.Width))
                        empty.Y = ((i * Me.pageSize.Height) + ((i + 1) * Me.PageSeparator.Height))
                        Dim location As Point = Point.Empty
                        location.X = (empty.X + Me.PageMargins.Left)
                        location.Y = (empty.Y + Me.PageMargins.Top)
                        Dim logicalPageBounds As New Rectangle((j * size5.Width), (i * size5.Height), size5.Width, size5.Height)
                        Dim pageBounds As New Rectangle(empty, Me.pageSize)
                        Dim viewablePageBounds As New Rectangle(location, size5)
                        Me.pageLayoutInfo.Add(New PageLayoutData(logicalPageBounds, pageBounds, viewablePageBounds, New Point(j, i)))
                    Next j
                Next i
            End If
        End Sub


        ' Properties
        Public Overrides ReadOnly Property Extent As Size
            Get
                Dim empty As Size = Size.Empty
                empty.Width = ((Me.rowColumns.Width * Me.pageSize.Width) + ((Me.rowColumns.Width + 1) * Me.PageSeparator.Width))
                empty.Height = ((Me.rowColumns.Height * Me.pageSize.Height) + ((Me.rowColumns.Height + 1) * Me.PageSeparator.Height))
                Return empty
            End Get
        End Property

        Private Property PageMargins As Margins
            Get
                Return Me.pageMargins
            End Get
            Set(ByVal value As Margins)
                Me.pageMargins = value
            End Set
        End Property

        Private Property PageSeparator As Size
            Get
                Return Me.pageSeparator
            End Get
            Set(ByVal value As Size)
                Me.pageSeparator = value
            End Set
        End Property

        Public Overrides ReadOnly Property RootDesignerAlignment As Point
            Get
                Dim empty As Point = Point.Empty
                Dim size As New Size((Me.pageSize.Width - (Me.PageMargins.Left + Me.PageMargins.Right)), (Me.pageSize.Height - (Me.PageMargins.Top + Me.PageMargins.Bottom)))
                Dim size2 As New Size((Me.rowColumns.Width * size.Width), (Me.rowColumns.Height * size.Height))
                Dim size3 As Size = If((Not MyBase.parentView.RootDesigner Is Nothing), MyBase.parentView.RootDesigner.Size, Size.Empty)
                Dim selectionSize As Size = WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize
                If Me.printDocument.PageSetupData.CenterHorizontally Then
                    empty.X = ((size2.Width - size3.Width) / 2)
                End If
                empty.X = Math.Max(empty.X, (selectionSize.Width + (selectionSize.Width / 2)))
                If Me.printDocument.PageSetupData.CenterVertically Then
                    empty.Y = ((size2.Height - size3.Height) / 2)
                End If
                empty.Y = Math.Max(empty.Y, (selectionSize.Height + (selectionSize.Height / 2)))
                Return empty
            End Get
        End Property

        Public Overrides ReadOnly Property Scaling As Single
            Get
                Return Me.scaling
            End Get
        End Property


        ' Fields
        Private Shared DefaultPageMargins As Margins = New Margins(20, 20, 20, 20)
        Private Shared DefaultPageSeparator As Size = New Size(30, 30)
        Private headerFooterMargins As Margins
        Private pageLayoutInfo As ArrayList
        Private pageMargins As Margins
        Private pageSeparator As Size
        Private pageSize As Size
        Private previewTime As DateTime
        Private printDocument As WorkflowPrintDocument
        Private rowColumns As Size
        Private scaling As Single

        ' Nested Types
        <StructLayout(LayoutKind.Sequential)> _
        Private Structure PageLayoutData
            Public LogicalPageBounds As Rectangle
            Public PageBounds As Rectangle
            Public ViewablePageBounds As Rectangle
            Public Position As Point
            Public Sub New(ByVal logicalPageBounds As Rectangle, ByVal pageBounds As Rectangle, ByVal viewablePageBounds As Rectangle, ByVal rowColumnPos As Point)
                Me.LogicalPageBounds = logicalPageBounds
                Me.PageBounds = pageBounds
                Me.ViewablePageBounds = viewablePageBounds
                Me.Position = rowColumnPos
            End Sub
        End Structure
    End Class
End Namespace

